/*
 * MIT License
 *
 * Copyright (c) 2023 北京凯特伟业科技有限公司
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.je.auth.check.context;

import com.je.auth.check.AuthCheckEngine;
import com.je.auth.check.context.model.AuthStorage;
import com.je.auth.check.context.model.AuthRequest;
import com.je.auth.check.context.model.AuthResponse;
import com.je.auth.check.exception.TokenException;

/**
 * 上下文处理器 [ThreadLocal版本]
 *
 * <p>
 * 使用 [ThreadLocal版本] 上下文处理器需要在全局过滤器或者拦截器内率先调用
 * SaTokenContextForThreadLocalStorage.setBox(req,res, sto) 初始化上下文
 * </p>
 *
 * @author kong
 */
public class AuthTokenContextForThreadLocal implements AuthTokenContext {

    private AuthCheckEngine authCheckEngine;

    @Override
    public AuthCheckEngine getAuthCheckEngine() {
        return authCheckEngine;
    }

    @Override
    public void setAuthCheckEngine(AuthCheckEngine authCheckEngine) {
        this.authCheckEngine = authCheckEngine;
    }

    /**
     * 基于 ThreadLocal 的 [Box存储器]
     */
    public static ThreadLocal<Box> boxThreadLocal = new InheritableThreadLocal<Box>();

    /**
     * 初始化 [Box存储器]
     *
     * @param request  {@link AuthRequest}
     * @param response {@link AuthResponse}
     * @param storage  {@link AuthStorage}
     */
    public void setBox(AuthRequest request, AuthResponse response, AuthStorage storage) {
        Box bok = new Box(request, response, storage);
        boxThreadLocal.set(bok);
    }

    /**
     * 清除 [Box存储器]
     */
    public void clearBox() {
        boxThreadLocal.remove();
    }

    /**
     * 获取 [Box存储器]
     *
     * @return see note
     */
    public Box getBox() {
        return boxThreadLocal.get();
    }

    /**
     * 获取 [Box存储器], 如果为空则抛出异常
     *
     * @return see note
     */
    public Box getBoxNotNull() {
        Box box = boxThreadLocal.get();
        if (box == null) {
            throw new TokenException("未成功初始化上下文");
        }
        return box;
    }

    @Override
    public AuthRequest getRequest() {
        return getBoxNotNull().getRequest();
    }

    @Override
    public AuthResponse getResponse() {
        return getBoxNotNull().getResponse();
    }

    @Override
    public AuthStorage getStorage() {
        return getBoxNotNull().getStorage();
    }

    @Override
    public boolean matchPath(String pattern, String path) {
        return false;
    }

    @Override
    public boolean isValid() {
        return getBox() != null;
    }

    /**
     * 临时内部类，用于存储[request、response、storage]三个对象
     *
     * @author kong
     */
    public static class Box {

        public AuthRequest request;

        public AuthResponse response;

        public AuthStorage storage;

        public Box(AuthRequest request, AuthResponse response, AuthStorage storage) {
            this.request = request;
            this.response = response;
            this.storage = storage;
        }

        public AuthRequest getRequest() {
            return request;
        }

        public void setRequest(AuthRequest request) {
            this.request = request;
        }

        public AuthResponse getResponse() {
            return response;
        }

        public void setResponse(AuthResponse response) {
            this.response = response;
        }

        public AuthStorage getStorage() {
            return storage;
        }

        public void setStorage(AuthStorage storage) {
            this.storage = storage;
        }

        @Override
        public String toString() {
            return "Box [request=" + request + ", response=" + response + ", storage=" + storage + "]";
        }

    }

}
